package com.hhdz.barrage.utils;

import android.os.Looper;
import android.util.Log;

public final class Logcat {

	private static boolean ENABLE_LOG = true;

	private static final boolean ENABLE_VERBOSE = true;
	private static final boolean ENABLE_DEBUG = true;
	private static final boolean ENABLE_INFO = true;
	private static final boolean ENABLE_WARN = true;
	private static final boolean ENABLE_ERROR = true;

	private static final boolean ENABLE_TRACE = true;
	private static final boolean ENABLE_TRACE_CALL = true;
	private static final boolean ENABLE_ASSERT = true;
	private static final boolean ENABLE_DEBUG_LOCK = true;

	private static final boolean ENABLE_LOG_META = true;
	private static final boolean ENABLE_LOG_TRACE_INFO = false;

	private static final String DEFAULT_TAG = "LOGCAT";

	private static ToStringExtension toStringExtension = new ToStringExtension() {

		@Override
		public String toString(Object obj) {
			return obj == null ? "null" : obj.toString();
		}

	};

	private static final void showLogo() {
		INFO("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM");
		INFO("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM");
		INFO("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM");
		INFO("MM.:  .:'   `:::  .:`MMMMMMMMMMM|`MMM'|MMMMMMMMMMM':  .:'   `:::  .:'.MM");
		INFO("MMMM.     :          `MMMMMMMMMM  :*'  MMMMMMMMMM'        :        .MMMM");
		INFO("MMMMM.    ::    .     `MMMMMMMM'  ::   `MMMMMMMM'   .     ::   .  .MMMMM");
		INFO("MMMMMM. :   :: ::'  :   :: ::'  :   :: ::'      :: ::'  :   :: ::.MMMMMM");
		INFO("MMMMMMM    ;::         ;::         ;::         ;::         ;::   MMMMMMM");
		INFO("MMMMMMM .:'   `:::  .:'   `:::  .:'   `:::  .:'   `:::  .:'   `::MMMMMMM");
		INFO("MMMMMM'     :           :           :           :           :    `MMMMMM");
		INFO("MMMMM'______::____      ::    .     ::    .     ::     ___._::____`MMMMM");
		INFO("MMMMMMMMMMMMMMMMMMM`---._ :: ::'  :   :: ::'  _.--::MMMMMMMMMMMMMMMMMMMM");
		INFO("MMMMMMMMMMMMMMMMMMMMMMMMMM::.         ::  .--MMMMMMMMMMMMMMMMMMMMMMMMMMM");
		INFO("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM-.     ;::-MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM");
		INFO("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM. .:' .MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM");
		INFO("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM.   .MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM");
		INFO("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\\ /MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM");
		INFO("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM");
		INFO("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM .:ZylvanaS:. MM");
		INFO("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM");
	}

	public static final void ENABLE() {
		ENABLE_LOG = true;

		showLogo();

		INFO("         ENABLE_VERBOSE: " + (ENABLE_VERBOSE ? "TRUE" : "FALSE"));
		INFO("           ENABLE_DEBUG: " + (ENABLE_DEBUG ? "TRUE" : "FALSE"));
		INFO("            ENABLE_INFO: " + (ENABLE_INFO ? "TRUE" : "FALSE"));
		INFO("            ENABLE_WARN: " + (ENABLE_WARN ? "TRUE" : "FALSE"));
		INFO("           ENABLE_ERROR: " + (ENABLE_ERROR ? "TRUE" : "FALSE"));
		INFO("           ENABLE_TRACE: " + (ENABLE_TRACE ? "TRUE" : "FALSE"));
		INFO("      ENABLE_TRACE_CALL: " + (ENABLE_TRACE_CALL ? "TRUE" : "FALSE"));
		INFO("          ENABLE_ASSERT: " + (ENABLE_ASSERT ? "TRUE" : "FALSE"));
		INFO("      ENABLE_DEBUG_LOCK: " + (ENABLE_DEBUG_LOCK ? "TRUE" : "FALSE"));
		INFO("        ENABLE_LOG_META: " + (ENABLE_LOG_META ? "TRUE" : "FALSE"));
		INFO("  ENABLE_LOG_TRACE_INFO: " + (ENABLE_LOG_TRACE_INFO ? "TRUE" : "FALSE"));
	}

	public static final void LOG(final String TAG, final String msg, final int traceLevel, final char logLevel) {
		if (!ENABLE_LOG) return;

		final String threadName = Thread.currentThread().getName();
		final int DEFAULT_TRACE_LEVEL = 4;
		final StackTraceElement trace = Thread.currentThread().getStackTrace()[DEFAULT_TRACE_LEVEL + traceLevel];
		final String fullClassName = trace.getClassName();
		final String className = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
		final String methodName = trace.getMethodName();
		final int lineNo = trace.getLineNumber();
		final String meta = ENABLE_LOG_META ? "[" + threadName + "]" + "<" + className + ":" + methodName + ":" + lineNo + "> " : "";
		final String traceInfo = ENABLE_LOG_TRACE_INFO ? " >>> at " + trace : "";
		switch (logLevel) {
		case ('v'):
			Log.v(TAG, meta + msg + traceInfo);
			break;
		case ('d'):
			Log.d(TAG, meta + msg + traceInfo);
			break;
		case ('i'):
			Log.i(TAG, meta + msg + traceInfo);
			break;
		case ('w'):
			Log.w(TAG, meta + msg + traceInfo);
			break;
		case ('e'):
			Log.e(TAG, meta + msg + traceInfo);
			break;
		}
	}

	public static final void LOG(final String msg, final char logLevel) {
		LOG(DEFAULT_TAG, msg, 1, logLevel);
	}

	public static final void VERBOSE(final String msg) {
		if (ENABLE_VERBOSE) LOG(msg, 'v');
	}

	public static final void DEBUG(final String msg) {
		if (ENABLE_DEBUG) LOG(msg, 'd');
	}

	public static final void INFO(final String msg) {
		if (ENABLE_INFO) LOG(msg, 'i');
	}

	public static final void WARN(final String msg) {
		if (ENABLE_WARN) LOG(msg, 'w');
	}

	public static final void ERROR(final String msg) {
		if (ENABLE_ERROR) LOG(msg, 'e');
	}

	public static final void ASSERT(final boolean cond, final String msg) {
		if (ENABLE_ASSERT && !cond) LOG("[ASSERTION FAILED] " + msg, 'e');
	}

	public static final void ASSERT(final boolean cond) {
		if (ENABLE_ASSERT && !cond) LOG("[ASSERTION FAILED]", 'e');
	}

	public static final void ASSERT_NOT_ON_UI_THREAD() {
		if (ENABLE_ASSERT && Thread.currentThread().getId() == Looper.getMainLooper().getThread().getId()) LOG("[ASSERTION FAILED] MUST NOT CALL ON UI THREAD", 'e');
	}

	public static final void DEBUG_LOCK(final String msg) {
		if (ENABLE_DEBUG_LOCK) LOG("[LOCK] " + msg, 'v');
	}

	public static final void NULL_CHECK(final Object obj) { // UNCONDITIONAL CHECK
		if (obj == null) throw new RuntimeException("NULL CHECK FAILED");
	}

	public static final void MARK() {
		if (ENABLE_TRACE) {
			LOG(DEFAULT_TAG, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", 0, 'v');
			LOG(DEFAULT_TAG, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", 0, 'v');
			LOG(DEFAULT_TAG, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", 0, 'v');
			LOG(DEFAULT_TAG, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", 0, 'v');
			LOG(DEFAULT_TAG, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", 0, 'v');
			LOG(DEFAULT_TAG, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", 0, 'v');
			LOG(DEFAULT_TAG, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", 0, 'v');
			LOG(DEFAULT_TAG, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", 0, 'v');
		}
	}

	public static final void TRACE_CALL(final Object... args) {
		if (!ENABLE_TRACE_CALL) return;
		if (args.length == 0) {
			LOG("()", 'v');
			return;
		}
		final StringBuilder sb = new StringBuilder(args.length * 7);
		sb.append('(');
		sb.append(toString(args[0]));
		for (int i = 1; i < args.length; i++)
			sb.append(", " + toString(args[i]));
		sb.append(')');
		LOG(sb.toString(), 'v');
	}

	public static final String toString(final Object obj) {
		return toStringExtension.toString(obj);
	}

	public static final void setToStringExtension(final ToStringExtension extension) {
		if (extension == null) return;
		toStringExtension = extension;
	}

	public static interface ToStringExtension {

		public String toString(Object obj);

	}

}
